package biz

import (
	"context"
	"github.com/ArtisanCloud/PowerWeChat/v3/src/miniProgram"
	"github.com/ArtisanCloud/PowerWeChat/v3/src/miniProgram/phoneNumber/response"
	"go.uber.org/zap"
	"lianzi_gos/internal/config"
	schema1 "lianzi_gos/internal/mods/rbac/schema"
	"lianzi_gos/pkg/cachex"
	"lianzi_gos/pkg/jwtx"
	"lianzi_gos/pkg/logging"
	"time"

	"lianzi_gos/internal/mods/mpweixin/dal"
	"lianzi_gos/internal/mods/mpweixin/schema"
	dal1 "lianzi_gos/internal/mods/rbac/dal"
	"lianzi_gos/pkg/errors"
	"lianzi_gos/pkg/util"
)

// 小程序用户端
type Member struct {
	Trans     *util.Trans
	MemberDAL *dal.Member
	StaffD    *dal.Staff
	UserDAL   *dal1.User

	Auth  jwtx.Auther
	Cache cachex.Cacher
}

// Query members from the data access object based on the provided parameters and options.
func (a *Member) Query(ctx context.Context, params schema.MemberQueryParam) (*schema.MemberQueryResult, error) {
	params.Pagination = true

	result, err := a.MemberDAL.Query(ctx, params, schema.MemberQueryOptions{
		QueryOptions: util.QueryOptions{
			OrderFields: []util.OrderByParam{
				{Field: "created_at", Direction: util.DESC},
			},
		},
	})
	if err != nil {
		return nil, err
	}
	return result, nil
}

// Get the specified member from the data access object.
func (a *Member) Get(ctx context.Context, id string) (*schema.Member, error) {
	member, err := a.MemberDAL.Get(ctx, id)
	if err != nil {
		return nil, err
	} else if member == nil {
		return nil, errors.NotFound("", "Member not found")
	}
	return member, nil
}

// Create a new member in the data access object.
func (a *Member) Create(ctx context.Context, formItem *schema.MemberForm) (*schema.Member, error) {
	member := &schema.Member{
		ID:        util.NewXID(),
		CreatedAt: time.Now(),
	}

	if err := formItem.FillTo(member); err != nil {
		return nil, err
	}

	err := a.Trans.Exec(ctx, func(ctx context.Context) error {
		if err := a.MemberDAL.Create(ctx, member); err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	return member, nil
}

// Update the specified member in the data access object.
func (a *Member) Update(ctx context.Context, id string, formItem *schema.MemberForm) error {
	member, err := a.MemberDAL.Get(ctx, id)
	if err != nil {
		return err
	} else if member == nil {
		return errors.NotFound("", "Member not found")
	}

	if err := formItem.FillTo(member); err != nil {
		return err
	}
	member.UpdatedAt = time.Now()

	return a.Trans.Exec(ctx, func(ctx context.Context) error {
		if err := a.MemberDAL.Update(ctx, member); err != nil {
			return err
		}
		return nil
	})
}

// Delete the specified member from the data access object.
func (a *Member) Delete(ctx context.Context, id string) error {
	exists, err := a.MemberDAL.Exists(ctx, id)
	if err != nil {
		return err
	} else if !exists {
		return errors.NotFound("", "Member not found")
	}

	return a.Trans.Exec(ctx, func(ctx context.Context) error {
		if err := a.MemberDAL.Delete(ctx, id); err != nil {
			return err
		}
		return nil
	})
}

/*
小程序 登录逻辑
用opened 解析 处理 如果已经有数据 判读是否绑定手机号
再去 比对 是否 是 员工 员工需要关联表
*/
func (a *Member) MiniWxLogin(ctx context.Context, code string) (*schema.MiniWxRes, error) {
	app, err := miniProgram.NewMiniProgram(&miniProgram.UserConfig{
		AppID:     config.C.MiniProgram.AppId,  // 小程序、公众号或者企业微信的appid
		Secret:    config.C.MiniProgram.Secret, // 商户号 appID
		HttpDebug: config.C.MiniProgram.IsDebug,
		Debug:     config.C.MiniProgram.IsDebug,
	})
	rs, err := app.Auth.Session(ctx, code)

	if err != nil {
		return nil, err
	}
	exists, err := a.MemberDAL.ExistsOpenid(ctx, rs.OpenID)
	if err != nil {
		return nil, err
	}

	if exists {
		user, err := a.MemberDAL.GetOpenid(ctx, rs.OpenID)

		if err != nil {
			return nil, err
		}

		userData := new(schema.MiniWxRes)
		user.Openid = ""
		userData.UserInfo = *user

		token, _ := a.genUserToken(ctx, user.ID)
		userData.Token = token
		if len(user.Phone) == 0 {
			userData.Status = -1 // 没有绑定手机号
		} else {
			userData.Status = 1 // 绑定手机号

		}
		return userData, nil
	} else {
		id := util.NewXID()
		member := &schema.Member{
			ID:        id,
			CreatedAt: time.Now(),
			Openid:    rs.OpenID,
			UserType:  "routine",
		}

		user := &schema1.User{
			ID:        id,
			CreatedAt: time.Now(),
			Openid:    rs.OpenID,
			UserType:  "routine",
			Status:    "activated",
		}

		err := a.Trans.Exec(ctx, func(ctx context.Context) error {
			if err := a.MemberDAL.Create(ctx, member); err != nil {
				return err
			}
			if err := a.UserDAL.Create(ctx, user); err != nil {
				return err
			}
			return nil
		})
		if err != nil {
			return nil, err
		}
		userData := new(schema.MiniWxRes)
		userData.UserInfo = *member

		token, _ := a.genUserToken(ctx, member.ID)
		userData.Token = token
		userData.Status = -2 // 新注册 需要上传 昵称 头像
		return userData, nil
	}
}

func (a *Member) GetPhone(ctx context.Context, code string) (*response.PhoneInfo, error) {
	app, err := miniProgram.NewMiniProgram(&miniProgram.UserConfig{
		AppID:     config.C.MiniProgram.AppId,  // 小程序、公众号或者企业微信的appid
		Secret:    config.C.MiniProgram.Secret, // 商户号 appID
		HttpDebug: config.C.MiniProgram.IsDebug,
		Debug:     config.C.MiniProgram.IsDebug,
	})
	if err != nil {
		return nil, err
	}
	rs, err := app.PhoneNumber.GetUserPhoneNumber(ctx, code)

	if err != nil {
		return nil, err
	}
	return rs.PhoneInfo, nil
}

/*
*
获取token
*/
func (a *Member) genUserToken(ctx context.Context, userID string) (string, error) {

	token, err := a.Auth.GenerateToken(ctx, userID)
	if err != nil {
		return "", err
	}

	tokenBuf, err := token.EncodeToJSON()
	if err != nil {
		return "", err
	}
	logging.Context(ctx).Info("小程序 user token", zap.Any("token", string(tokenBuf)))
	return token.GetAccessToken(), nil

}

/*
*
小程序 更新 手机号
*/
func (a *Member) UpdatePhone(ctx context.Context, updateItem *schema.UpdatePhone) (int, error) {
	mID := util.FromUserID(ctx)
	member, err := a.MemberDAL.Get(ctx, mID, schema.MemberQueryOptions{
		QueryOptions: util.QueryOptions{
			SelectFields: []string{"phone"},
		},
	})

	if err != nil {
		return 0, err
	}
	if member.Phone != "" {
		return -1, nil
	}
	err = a.MemberDAL.UpdatePhoneByID(ctx, mID, updateItem.Phone)
	if err != nil {
		return 0, err
	}
	return 1, nil
} /*
*
小程序 头像  昵称
*/
func (a *Member) UpdateNicknameAvatar(ctx context.Context, updateItem *schema.UpdateNicknameAvatar) (int, error) {
	mID := util.FromUserID(ctx)
	member, err := a.MemberDAL.Get(ctx, mID, schema.MemberQueryOptions{
		QueryOptions: util.QueryOptions{
			SelectFields: []string{"nickname", "avatar"},
		},
	})

	if err != nil {
		return 0, err
	}
	if member.ID != "" {
		return -1, nil
	}
	err = a.MemberDAL.UpdateNicknameAvatarByID(ctx, mID, updateItem.Avatar, updateItem.Nickname)
	if err != nil {
		return 0, err
	}
	return 1, nil
}

// Get user info
func (a *Member) GetUserInfo(ctx context.Context) (*schema.Member, error) {

	userID := util.FromUserID(ctx)
	user, err := a.MemberDAL.Get(ctx, userID, schema.MemberQueryOptions{
		QueryOptions: util.QueryOptions{
			OmitFields: []string{"openid"},
		},
	})

	if err != nil {
		return nil, err
	} else if user == nil {
		return nil, errors.NotFound("", "暂无当前用户")
	}
	if len(user.Phone) > 0 {

		ok, _ := a.StaffD.ExistsPhone(ctx, user.Phone)
		if ok {
			user.IsAuth = true
		} else {
			user.IsAuth = false
		}
		ok, _ = a.StaffD.ExistsPhoneAdmin(ctx, user.Phone)
		if ok {
			user.IsAdmin = true
		} else {
			user.IsAdmin = false
		}

	}

	return user, nil
}
